package com.servicelayer.base;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.hibernate.Session;

import com.core.protocols.IHibernateDelegate;
import com.core.protocols.IHibernateFetchRequestDelegate;
import com.core.protocols.IHibernateParentEnumeratorDelegate;
import com.core.protocols.IKVObject;
import com.core.protocols.IServiceLayerDelegate;
import com.managers.hibernate.ExceptionHandler;
import com.managers.hibernate.HibernateFetchRequest;
import com.managers.hibernate.exceptionevent.ExceptionEvent;
import com.model.KeyValue;

public abstract class HibernateServiceLayer
        extends ServiceLayer
        implements IHibernateFetchRequestDelegate {


    private Serializable userInfo       = null;
    private Set <String> expandEntities = null;



    abstract public void enumerateParentObjectsWithDelegate ( IKVObject kvObject,
                                                              IHibernateParentEnumeratorDelegate delegate );



    abstract public Class <? extends IKVObject> entityClass ();



    public Object getUserInfo () {

        return userInfo;
    }



    public void setUserInfo ( Serializable userInfo ) {

        this.userInfo = userInfo;
    }



    public Set <String> getExpandEntities () {

        return expandEntities;
    }



    public void setExpandEntities ( Set <String> expandEntities ) {

        this.expandEntities = expandEntities;
    }



    @Override
    public <T> void hibernateFetchResponse ( IHibernateDelegate request,
                                             List <T> response,
                                             Exception exception ) {

        request.setDelegate(null);

        IServiceLayerDelegate delegate = this.getLayerDelegate();
        if ( delegate == null ) {
            return;
        }

        delegate.responseResponseItemsList(response, this, exception);

    }



    @Override
    public void performRequestWithFilter ( String predicate ) {

        // assert selectionCriteria != null;

        Class <?> entityClass = this.entityClass();
        assert (entityClass != null) : "hibernate service layer entityClass==null";

        HibernateFetchRequest request = new HibernateFetchRequest();
        request.setSelectionCriteria(this.selectionCriteria);
        request.setUserInfo(this.userInfo);
        request.setDelegate(this);
        request.setExpandEntities(this.expandEntities);
        request.performFetch(entityClass, predicate);
    }



    protected static void sendObject ( HibernateServiceLayer layer,
                                       IKVObject object,
                                       IServiceLayerDelegate delegate,
                                       Exception exception ) {

        if ( delegate == null ) {
            return;
        }
        List <IKVObject> list = null;
        if ( object != null ) {
            list = new ArrayList <IKVObject>();
            list.add(object);
        }
        delegate.responseResponseItemsList(list, layer, exception);

    }



    public static IKVObject createEntityWithTemplate ( IKVObject template,
                                                       IServiceLayerDelegate delegate,
                                                       Session session )
            throws Exception {

        IKVObject result = HibernateFetchRequest.createEntityWithTemplate(template, session);
        HibernateServiceLayer.sendObject(null, result, delegate, null);

        return result;

    }



    public IKVObject mergeEntityByIDWithTemplate ( Integer id,
                                                   IKVObject template,
                                                   IServiceLayerDelegate delegate ) {

        IKVObject result = null;
        Exception exception = null;

        try {
            result = HibernateFetchRequest.mergeEntityByIDWithTemplate(id, template);

        } catch ( Exception e ) {
            ExceptionHandler.handleException(e, new ExceptionEvent(ExceptionEvent.MERGEOBJECT));
        } finally {
            HibernateServiceLayer.sendObject(this, result, delegate, exception);
        }

        return result;
    }



    public IKVObject objectByUNID ( Integer unid,
                                    Session externalSession,
                                    IServiceLayerDelegate delegate ) {

        IKVObject result = HibernateFetchRequest.objectByUNID(this.entityClass(), unid, externalSession);
        HibernateServiceLayer.sendObject(this, result, delegate, null);

        return result;
    }



    public void setCustomProperty ( Integer unid,
                                    KeyValue property,
                                    IServiceLayerDelegate delegate ) {

        Exception exception = null;
        IKVObject result = null;
        try {
            result = HibernateFetchRequest.setCustomPropertyValue(this.entityClass(), unid, property);

        } catch ( Exception e ) {
            exception = new Exception(e.getMessage());
        } finally {
            HibernateServiceLayer.sendObject(this, result, delegate, exception);
        }

    }



    public void deleteObject ( String objectId ) {

        String predicate = String.format("where id = %s", objectId);

        HibernateFetchRequest request = new HibernateFetchRequest();
        request.setSelectionCriteria(this.selectionCriteria);
        request.setDelegate(this);
        request.performDelete(this.entityClass(), predicate);

    }



}
